package com.yixing.tech.system.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.yixing.tech.common.base.BaseMongoDao;
import com.yixing.tech.common.base.BusinessException;
import com.yixing.tech.common.enums.ErrCode;
import com.yixing.tech.common.enums.Status;
import com.yixing.tech.common.enums.UserType;
import com.yixing.tech.common.enums.YesOrNo;
import com.yixing.tech.system.entity.WxLoginResponse;
import com.yixing.tech.system.po.*;
import com.yixing.tech.system.service.IPortalService;
import com.yixing.tech.system.utils.PortalConfig;
import com.yixing.tech.common.utils.CommonUtil;
import com.yixing.tech.common.utils.DataUtil;
import com.yixing.tech.common.utils.MD5Util;
import com.yixing.tech.common.vo.s3.ApplicationVO;
import com.yixing.tech.common.vo.s3.RoleVO;
import com.yixing.tech.common.vo.s3.TenantVO;
import com.yixing.tech.common.vo.s3.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author yixing tech
 * at 2022/3/9
 * describe：
 */
@Service
@Slf4j
public class PortalServiceImpl implements IPortalService {

    @Resource
    private BaseMongoDao baseMongoDao;
    @Resource
    private MongoTemplate mongoTemplate;

    @Value("${official-manager-id}")
    private String officialManagerId;
    @Value("${official-tenant-id}")
    private String officialTenantId;

    /**
     * 应用类型是小程序
     */
    private String appletType = "6255692a3ad7884c25d9a10d";
    /**
     * 应用类型是H5
     */
    private String h5Type = "664aaee5fd242f0f4e0d4f82";
    /**
     * 应用类型是web
     */
    private String webType = "6255691c3ad7884c25d9a10c";


    @Override
    public UserVO login(UserVO vo, String appType) throws BusinessException {
        String loginName = vo.getLoginName();
        if (!StringUtils.hasText(loginName)) {
            throw new BusinessException(ErrCode.PARAMETER_ERROR);
        }

        String tenantId = vo.getTenantId();
        if (!StringUtils.hasText(tenantId)) {
            String tenantCode = vo.getTenantCode();
            if (!StringUtils.hasText(tenantCode)) {
                TenantVO cond1 = new TenantVO();
                cond1.setName(loginName);
                Tenant tenant = baseMongoDao.queryOne(Tenant.class, cond1);
                if (tenant == null) {
                    //默认鑫常
                    tenantId = "625d6c49249618079eedd1da";
                }else tenantId = tenant.getId();

            } else {

                TenantVO cond1 = new TenantVO();
                cond1.setCode(tenantCode);
                Tenant tenant = baseMongoDao.queryOne(Tenant.class, cond1);
                if (tenant == null) {
                    throw new BusinessException(ErrCode.TENANT_FREEZE);
                }
                tenantId = tenant.getId();

            }
        }
        Criteria andCriteria = new Criteria();
        Criteria orCriteria = new Criteria();
        orCriteria.orOperator(Criteria.where("loginName").is(loginName), Criteria.where("phone").is(loginName));
        andCriteria.andOperator(Criteria.where("status").is(Status.def.ordinal()).and("isDelete").ne(YesOrNo.YES.ordinal()).and("tenantId").is(tenantId), orCriteria);
        User user = mongoTemplate.findOne(Query.query(andCriteria), User.class);
        if (user == null) {
            throw new BusinessException(ErrCode.USER_NOT_EXIST);
        }
        String desPassword = vo.getPassword();
        String md5Password = MD5Util.MD5(desPassword);
        if (!md5Password.equals(user.getPassword())) {
            throw new BusinessException(ErrCode.USER_PASSWORD_ERROR);
        }
        user.setPassword(null);
        return fillUser(user, appType);
    }

    /**
     * 登录
     */
    @Override
    public UserVO queryLoginInfo(SystemUser systemUser) throws BusinessException {
//        Criteria andCriteria = new Criteria();
//        Criteria orCriteria = new Criteria();
//        orCriteria.orOperator(Criteria.where("loginName").is(loginName), Criteria.where("phone").is(loginName));
//        andCriteria.andOperator(Criteria.where("status").is(Status.def.ordinal()).and("isDelete").ne(YesOrNo.YES.ordinal()).and("tenantId").is(tenantCode), orCriteria);
//        User user = mongoTemplate.findOne(Query.query(andCriteria), User.class);
//        if (user == null) {
//            throw new BusinessException(ErrCode.USER_NOT_EXIST);
//        }
//        String desPassword = vo.getPassword();
//        String md5Password = MD5Util.MD5(desPassword);
//        if (!md5Password.equals(user.getPassword())) {
//            throw new BusinessException(ErrCode.USER_PASSWORD_ERROR);
//        }
//        user.setPassword(null);
//        return fillUser(user, appType);

        return null;
    }

    @Override
    public UserVO loginWeb(UserVO vo) throws BusinessException {
        return login(vo, webType);
    }

    @Override
    public UserVO loginRefresh(String userId) throws BusinessException {
        User user = baseMongoDao.get(userId, User.class);
        if (user == null) {
            throw new BusinessException(ErrCode.USER_NOT_EXIST);
        }
        return fillUser(user, webType);
    }
    @Override
    public UserVO loginH5(UserVO vo) throws BusinessException {
        return login(vo, h5Type);
    }
    private UserVO fillUser(User user,  String appType) throws BusinessException {
        TenantVO cond1 = new TenantVO();
        cond1.setId(user.getTenantId());
        cond1.setStatus(Status.def.ordinal());
        Tenant tenant = baseMongoDao.queryOne(Tenant.class, cond1);
        if (tenant == null) {
            throw new BusinessException(ErrCode.TENANT_FREEZE);
        }
        UserVO userVO = DataUtil.o2o(user, UserVO.class);
        userVO.setTenant(DataUtil.o2o(tenant, TenantVO.class));
        List<ApplicationVO> apps = null;
        if (user.getIsSuper()) {
            if (!webType.equals(appType))
                throw new BusinessException(ErrCode.USER_NOT_EXIST);
            apps = new ArrayList<>();
            Application app = baseMongoDao.get(officialManagerId, Application.class);
            apps.add(DataUtil.o2o(app, ApplicationVO.class));
        } else {
            Role role = user.getRole();
            Role selfRole = user.getSelfRole();
            if (null == role && selfRole == null) {
                throw new BusinessException(ErrCode.USER_NO_ROLE);
            }

            Set<String> appIds = new HashSet<>();
            if (role != null) {
                role = baseMongoDao.get(role.getId(), Role.class);
                appIds.addAll(role.getApplicationIds() == null ? Collections.emptySet() : role.getApplicationIds());
                userVO.setRole(DataUtil.o2o(role, RoleVO.class));

            }
            if (selfRole != null && null != selfRole.getApplicationIds()) {
                appIds.addAll(selfRole.getApplicationIds());
            }
            if (!CommonUtil.listIsBlank(appIds)) {
                apps = baseMongoDao.batchQuery(new ArrayList<>(appIds), Application.class, ApplicationVO.class);
                //返回小程序应用
                int size = apps.size();
                for (int i = size - 1; i >= 0; i--) {
                    ApplicationVO a = apps.get(i);
                    if (!a.getType().getId().equals(appType)) apps.remove(i);
                }
            }

        }
        userVO.setApplications(apps);

        return userVO;
    }

    @Override
    public UserVO loginApplet(UserVO vo) throws BusinessException {
        return login(vo, appletType);
    }

    @Override
    public UserVO downLogin(String adminId, UserVO loginUser) throws BusinessException {
        User user = baseMongoDao.get(adminId, User.class);
        if (user == null) {
            throw new BusinessException(ErrCode.USER_NOT_EXIST);
        }
        Role role = user.getRole();
        Role selfRole = user.getSelfRole();
        if (null == role && selfRole == null) {
            throw new BusinessException(ErrCode.USER_NO_ROLE);
        }
        if (!isParentTenant(loginUser.getTenantId(), user.getTenantId())) {
            throw new BusinessException(ErrCode.UNAUTHORIZED);
        }
        TenantVO cond = new TenantVO();
        cond.setId(user.getTenantId());
        cond.setStatus(Status.def.ordinal());
        Tenant tenant = baseMongoDao.queryOne(Tenant.class, cond);
        if (tenant == null) {
            throw new BusinessException(ErrCode.TENANT_FREEZE);
        }
        user.setPassword(null);
        UserVO userVO = DataUtil.o2o(user, UserVO.class);
        userVO.setTenant(DataUtil.o2o(tenant, TenantVO.class));

        Set<String> appIds = new HashSet<>();
        if (role != null) {
            role = baseMongoDao.get(role.getId(), Role.class);
            userVO.setRole(DataUtil.o2o(role, RoleVO.class));
            appIds.addAll(role.getApplicationIds());
        }
        if (selfRole != null) {
            appIds.addAll(selfRole.getApplicationIds());
        }

        if (!CommonUtil.listIsBlank(appIds)) {
            List<ApplicationVO> apps = baseMongoDao.batchQuery(new ArrayList<>(appIds), Application.class, ApplicationVO.class);
            userVO.setApplications(apps);
        }
        return userVO;
    }

    @Override
    public UserVO wxLogin(String jsCode, String tenantId, String roleId) throws BusinessException {
        if (null == tenantId) tenantId = officialTenantId;
        RestTemplate restTemplate = new RestTemplate();
        TenantVO cond = new TenantVO();
        cond.setId(tenantId);
        cond.setStatus(Status.def.ordinal());
        Tenant tenant = baseMongoDao.queryOne(Tenant.class, cond);
        if (tenant == null) {
            throw new BusinessException(ErrCode.TENANT_FREEZE);
        }
        String wpStr = restTemplate.getForObject(PortalConfig.wxLoginHttp, String.class, tenant.getAppletAppId(), tenant.getAppletSecret(), jsCode);
        WxLoginResponse wp = JSONObject.parseObject(wpStr, WxLoginResponse.class);
        if (wp.isOk()) {
            String loginName = wp.getUnionid();
            if (!StringUtils.hasText(loginName))
                throw new BusinessException(ErrCode.PARAMETER_ERROR, wp.getErrcode() + wp.getErrmsg());
            UserVO c = new UserVO();
            c.setLoginName(loginName);
            c.setStatus(Status.def.ordinal());
            c.setTenantId(tenantId);
            User user = baseMongoDao.queryOne(User.class, c);
            if (user == null) {
                String md5Password = CommonUtil.buildDefaultPassword(loginName);
                user = new User();
                user.setIsSuper(false);
                user.setIsAdmin(false);
                user.setStatus(Status.def.ordinal());
                user.setPassword(md5Password);
                user.setLoginName(loginName);
                user.setSessionKey(wp.getSession_key());
                Role role = new Role();
                role.setId(roleId);
                user.setRole(role);
                user.setTenantId(tenantId);
                user.setName("wx_微信用户");
                user.setType(UserType.微信用户);
                user = baseMongoDao.save(user);
            } else {
            }
            user.setPassword(null);
            UserVO userVO = fillUser(user, appletType);
            return userVO;
        } else {
            throw new BusinessException(ErrCode.PARAMETER_ERROR, wp.getErrcode() + wp.getErrmsg());
        }

    }

    private boolean isParentTenant(String parentId, String childId) {
        TenantVO cond = new TenantVO();
        cond.setId(childId);
        cond.setParentId(parentId);
        return baseMongoDao.exists(cond, Tenant.class);
    }

}
